package com.unitd.modules.sys.service.impl;

import com.unitd.comm.constant.ToolConstant;
import com.unitd.frame.comm.tree.Ztree;
import com.unitd.frame.comm.utils.DateUtils;
import com.unitd.frame.comm.utils.ListUtils;
import com.unitd.frame.comm.utils.StringUtils;
import com.unitd.frame.mybatis.core.dao.IBaseDao;
import com.unitd.frame.mybatis.core.service.impl.BaseServiceImpl;
import com.unitd.modules.sys.dao.ISysMenuDao;
import com.unitd.modules.sys.dao.ISysRoleMenuDao;
import com.unitd.modules.sys.entity.SysMenu;
import com.unitd.modules.sys.entity.SysRoleMenu;
import com.unitd.modules.sys.service.ISysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @desc 菜单信息表业务逻辑控制接口实现类
 * @filename SysMenuServiceImpl.java
 * @copyright www.unitd.com
 * @author Hudan
 * @version 1.0
 * @date 2017-04-08
 */
@Service("sysMenuService")
public class SysMenuServiceImpl extends BaseServiceImpl<SysMenu, String> implements ISysMenuService {

	@Autowired
	private ISysMenuDao sysMenuDao;
	@Autowired
	private ISysRoleMenuDao sysRoleMenuDao;

	/**
	 * @return GenericDao实现类
	 * @desc 定义成抽象方法, 由子类实现, 完成dao的注入
	 */
	@Override
	public IBaseDao<SysMenu, String> getDao() {
		return sysMenuDao;
	}

	/**
	 * @desc 插入之前执行方法, 需要手工调用
	 * @param sysMenu 数据保存对象
	 * @param userId 操作人
	 */
	private void preInsert(SysMenu sysMenu, String userId) {
		sysMenu.setId(getPrePrimaryKey(sysMenu.getParentId()));
		sysMenu.setCreateBy(userId);
		sysMenu.setCreateDate(DateUtils.formatDate(new Date(), DateUtils.TIMESTAMP_PATTERN));
	}

	/**
	 * @desc 更新之前执行方法，需要手动调用
	 * @param sysMenu 数据保存对象
	 * @param userId 操作人
	 */
	private void preUpdate(SysMenu sysMenu, String userId){
		sysMenu.setUpdateBy(userId);
		sysMenu.setUpdateDate(DateUtils.formatDate(new Date(), DateUtils.TIMESTAMP_PATTERN));
	}

	/**
	 * @desc 根据主键ID获取对应的详情信息
	 * @param id 主键ID
	 * @return 菜单详情
	 */
	@Override
	public SysMenu findBy(String id) {
		SysMenu sysMenu = new SysMenu("0");            // 默认新建的菜单为目录(菜单类型 -1:目录;0:菜单; 1:功能)
		if (!StringUtils.isZero(id)) {
			sysMenu = sysMenuDao.findBy(id);
		}
		return sysMenu;
	}

	/**
	 * @desc 获取所有有效菜单, 并按照层级关系进行重新组合
	 * @return 按照层级关系排列的树
	 */
	@Override
	public List<Ztree> getSysMenuTrees() {
		// 从数据库中取出所有有效的菜单
		List<SysMenu> menus = sysMenuDao.findAllData();
		// 对菜单列表按照层级关系进行排序
		return sortMenus(menus, "-1");
	}

	/**
	 * @desc 根据选择的菜单父ID获取该父菜单下的最大sort值并+1
	 * @param parentId 父菜单ID
	 * @return 某父菜单下的最大排序
	 */
	@Override
	public Integer getMaxSortByPId(String parentId) {
		return sysMenuDao.getMaxSortByPId(parentId);
	}

	/**
	 * @desc 根据选择的菜单父ID及菜单类型,获取新增此菜单的主键ID
	 * @param parentId 父菜单ID
	 * @return 某父菜单下的最大子ID
	 */
	@Override
	public String getPrePrimaryKey(String parentId) {
		String menuType;
		if("-1".equals(parentId)) menuType = "-1";
		else {
			SysMenu sysMenu = sysMenuDao.findBy(parentId);
			menuType = sysMenu.getType();
		}
		return sysMenuDao.getPrePrimaryKey(menuType, parentId);
	}

	/**
	 * @desc 获取指定用户具有权限的层级菜单信息列表(一般为顶级,一级,二级共三级菜单)
	 * @param userId 指定的用户
	 * @return 用户菜单列表
	 */
	@Override
	@Cacheable(value = "findTreeListByUserId", key = "#userId")
	public List<SysMenu> findTreeListByUserId(String userId) {
		// 先获取顶级菜单
		List<SysMenu> rootList = sysMenuDao.findListByUserIdAndPId(userId, "-1");
		if(ListUtils.isNull(rootList)) {
			return null;
		}

		// 处理层级关系,获取顶级菜单下一级菜单
		for (SysMenu root : rootList) {
			List<SysMenu> firstList = sysMenuDao.findListByUserIdAndPId(userId, root.getId());
			if(!ListUtils.isNull(firstList)) {
				root.setSonList(firstList);

				// 循环获取一级菜单下的二级菜单
				for(SysMenu first : firstList) {
					List<SysMenu> secondList = sysMenuDao.findListByUserIdAndPId(userId, first.getId());
					if(!ListUtils.isNull(secondList)) {
						first.setSonList(secondList);
					}
				}
			}
		}
		return rootList;
	}

	/**
	 * @desc 处理数据保存/更新
	 * @param param 前端传送的需要处理的数据
	 * @return 数据保存/更新结果
	 */
	@Override
	@Transactional(rollbackFor={RuntimeException.class, Exception.class, Throwable.class})
	public Integer doEdit(Map<String, Object> param) {
		Integer result = 0;
		SysMenu sysMenu = (SysMenu) param.get(SysMenu.class.getName());
		String userId = (String) param.get(ToolConstant.USER_TOKEN_ID);

		if (sysMenu != null) {
			if (!StringUtils.isZero(sysMenu.getId())) {
				preUpdate(sysMenu, userId);
				sysMenuDao.updateByPrimaryKeySelective(sysMenu);
			} else {
				preInsert(sysMenu, userId);
				sysMenuDao.insertSelective(sysMenu);

				// 插入对应的超级管理员的角色-菜单关联信息
				SysRoleMenu sysRoleMenu = new SysRoleMenu("1", sysMenu.getId());
				sysRoleMenuDao.insertSelective(sysRoleMenu);
			}
		}
		return result;
	}

	/**
	 * @desc 根据ID串删除菜单(同时还需要删除对应的角色-菜单关联信息)
	 * @param ids 需要删除的详情信息ID串,多个ID之间用,分割
	 * @return 删除记录条数
	 */
	@Override
	@Transactional(rollbackFor={RuntimeException.class, Exception.class, Throwable.class})
	public Integer doDelete(String ids) {
		Integer result = 0;

		List<String> idList = StringUtils.toList(ids, ",");
		SysMenu param = new SysMenu(); 								// 删除方法的参数对象
		for(String id : idList) {
			param.setId(id); 										// 设置参数

			// 逻辑删除
			result += sysMenuDao.deleteByDelFlag(param);
		}
		return result;
	}

	/**
	 * @desc 获取进行了递归处理的菜单树,同时,在树的最顶层包装一个虚拟菜单
	 * @param sysMenus 所有有效的菜单列表
	 * @param pId      上级菜单ID
	 * @return 树结果对象
	 */
	private List<Ztree> sortMenus(List<SysMenu> sysMenus, String pId) {
		List<Ztree> trees = new ArrayList<>();
		// 如果是顶级菜单,先建立一个菜单跟节点
		Ztree root = new Ztree();
		root.setId("-1"); 											// 菜单ID
		root.setName("顶级菜单"); 									// 菜单名称
		root.setpId(""); 											// 上级菜单
		root.setChildren(recursionMenus(sysMenus, pId));
		trees.add(root);

		return trees;
	}

	/**
	 * @desc 递归处理多级菜单树,将菜单按照树进行分组处理
	 * @param sysMenus 所有有效的菜单列表
	 * @param pId      上级菜单ID
	 * @return 树结构对象
	 */
	private List<Ztree> recursionMenus(List<SysMenu> sysMenus, String pId) {
		List<Ztree> result = new ArrayList<>();

		Ztree vo; 														// 子节点对象
		for (SysMenu sysMenu : sysMenus) {
			vo = new Ztree();
			vo.setId(sysMenu.getId()); 									// 菜单ID
			vo.setName(sysMenu.getName()); 								// 菜单名称
			vo.setpId(sysMenu.getParentId()); 							// 上级菜单

			String parentId = sysMenu.getParentId(); 					// 获取菜单的父id
			if (StringUtils.isNotBlank(parentId)) {
				if (parentId.equals(pId)) {
					vo.setChildren(recursionMenus(sysMenus, sysMenu.getId()));
					result.add(vo);
				}
			}
		}
		return result;
	}

//
//	/**
//	 * @desc 获取指定用户具有权限的菜单URL列表
//	 * @param userId 指定的用户
//	 * @return
//	 */
//	@Override
////	@Cacheable(value = "findUrlsByUserId", key = "#userId")
//	public List<String> findUrlsByUserId(String userId) {
//		List<String> urlList = new ArrayList<>();
//
//		// 先获取指定用户下的所有权限菜单信息列表
//		List<SysMenu> resList = sysMenuDao.findListByUserId(userId);
//		if (resList == null) {
//			return new ArrayList<>();
//		}
//
//		// 遍历组装URL
//		for (SysMenu res : resList) {
//			if (StringUtils.isNoneBlank(res.getUrl())) {
//				urlList.add(res.getUrl());
//			}
//		}
//		return urlList;
//	}

}